package top.wuchu.rpc.transport.socket.server;

import top.wuchu.rpc.factory.ThreadPoolFactory;
import top.wuchu.rpc.handler.RequestHandler;
import top.wuchu.rpc.hook.ShutdownHook;
import top.wuchu.rpc.provider.ServiceProviderImpl;
import top.wuchu.rpc.registry.NacosServiceRegistry;
import top.wuchu.rpc.serializer.CommonSerializer;
import top.wuchu.rpc.transport.AbstractRpcServer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;

/**
 * Socket方式远程方法调用的提供者（服务端）
 *
 * @author Wuchu
 */
public class SocketServer extends AbstractRpcServer {

    private final ExecutorService threadPool;
    private final CommonSerializer serializer;
    private final RequestHandler requestHandler = new RequestHandler();

    public SocketServer(String host, int port) {
        this(host, port, DEFAULT_SERIALIZER);
    }

    public SocketServer(String host, int port, Integer serializer) {
        this.host = host;
        this.port = port;
        threadPool = ThreadPoolFactory.createDefaultThreadPool("socket-rpc-server");
        this.serviceRegistry = new NacosServiceRegistry();
        this.serviceProvider = new ServiceProviderImpl();
        this.serializer = CommonSerializer.getByCode(serializer);

        // 扫描当前服务提供者的所有服务，并添加到注册中心
        scanServices();
    }

    /**
     * 服务提供方使用一个SocketServer来进行相关的服务注册、接收客户端的请求并处理
     */
    @Override
    public void start() {
        try (ServerSocket serverSocket = new ServerSocket()) {
            serverSocket.bind(new InetSocketAddress(host, port));
            logger.info("服务器启动……");

            // 如果服务崩了启动后备清除计划
            ShutdownHook.getShutdownHook().addClearAllHook();

            // 因为可能有很多客户端来请求这个服务，将每个客户端的请求都交给一个任务线程去处理
            // serverSocket.accept() 获取请求的客户端socket
            Socket socket;
            while ((socket = serverSocket.accept()) != null) {
                logger.info("消费者连接: {}:{}", socket.getInetAddress(), socket.getPort());
                threadPool.execute(new SocketRequestHandlerThread(socket, requestHandler, serializer));
            }

            // 调用 shutdown() 方法后线程池会在执行完正在执行的任务和队列中等待的任务后才彻底关闭。
            threadPool.shutdown();
        } catch (IOException e) {
            logger.error("服务器启动时有错误发生:", e);
        }
    }

}
